package api

import (
	"fmt"
	"math"
	"math/big"
	"strconv"
	"kumachan/standalone/util"
	"kumachan/interpreter/runtime/rt"
)


func __IntegerEqual(a *big.Int, b *big.Int) rt.EnumValue {
	return rt.ToBool(a.Cmp(b) == 0)
}
func __IntegerLessThan(a *big.Int, b *big.Int) rt.EnumValue {
	return rt.ToBool(a.Cmp(b) == -1)
}
func __IntegerCompare(a *big.Int, b *big.Int) rt.EnumValue {
	var result = a.Cmp(b)
	if result < 0 {
		return rt.ToOrdering(rt.Smaller)
	} else if result > 0 {
		return rt.ToOrdering(rt.Bigger)
	} else {
		return rt.ToOrdering(rt.Equal)
	}
}

func __FloatEqual(a float64, b float64) rt.EnumValue {
	return rt.ToBool(a == b)
}
func __FloatLessThan(a float64, b float64) rt.EnumValue {
	return rt.ToBool(a < b)
}

func __IntegerToString(n *big.Int) string {
	return n.String()
}
func __FloatToString(x float64) string {
	return fmt.Sprint(x)
}
func __Percentage0(x float64) string {
	return fmt.Sprintf("%.0f%%", (100 * x))
}
func __Percentage1(x float64) string {
	return fmt.Sprintf("%.1f%%", (100 * x))
}
func __Percentage2(x float64) string {
	return fmt.Sprintf("%.2f%%", (100 * x))
}

func __NormalFloatParse(str string) rt.EnumValue {
	var x, err = strconv.ParseFloat(str, 64)
	if err != nil || !(util.IsNormalFloat(x)) {
		return rt.None()
	} else {
		return rt.Some(x)
	}
}

func __IntegerToFloat(n *big.Int) float64 {
	var f = big.NewFloat(0)
	f.SetInt(n)
	var x, acc = f.Float64()
	if acc == big.Exact {
		return x
	} else {
		return math.Inf(f.Sign())
	}
}
func __NormalFloatToInteger(x float64) *big.Int {
	if !(util.IsNormalFloat(x)) { panic("something went wrong") }
	var f = big.NewFloat(x)
	var n, _ = f.Int(nil)
	return n
}

func __IntegerToMaybeNumber(n *big.Int) rt.EnumValue {
	if util.IsNonNegative(n) {
		return rt.Some(n)
	} else {
		return rt.None()
	}
}
func __FloatToMaybeNormalFloat(x float64) rt.EnumValue {
	if util.IsNormalFloat(x) {
		return rt.Some(x)
	} else {
		return rt.None()
	}
}


func __IntegerPlus(a *big.Int, b *big.Int) *big.Int {
	var c big.Int
	return c.Add(a, b)
}
func __IntegerMinus(a *big.Int, b *big.Int) *big.Int {
	var c big.Int
	return c.Sub(a, b)
}
func __IntegerNegate(n *big.Int) *big.Int {
	var m big.Int
	m.Neg(n)
	return &m
}
func __IntegerMul(a *big.Int, b *big.Int) *big.Int {
	var c big.Int
	return c.Mul(a, b)
}
func __IntegerQuo(a *big.Int, b *big.Int) *big.Int {
	var q, r big.Int
	q.QuoRem(a, b, &r)
	return &q
}
func __IntegerRem(a *big.Int, b *big.Int) *big.Int {
	var q, r big.Int
	q.QuoRem(a, b, &r)
	return &r
}
func __IntegerPow(a *big.Int, b *big.Int) *big.Int {
	var c big.Int
	c.Exp(a, b, nil)
	return &c
}
func __NumberForceMinus(a *big.Int, b *big.Int) *big.Int {
	var c big.Int
	c.Sub(a, b)
	if c.Cmp(big.NewInt(0)) >= 0 {
		return &c
	} else {
		panic("number subtraction underflow")
	}
}

func __Plus(a float64, b float64) float64 { return a + b }
func __Minus(a float64, b float64) float64 { return a - b }
func __Negate(x float64) float64 { return -x }
func __Mul(a float64, b float64) float64 { return a * b }
func __Quo(a float64, b float64) float64 { return a / b }
func __Rem(a float64, b float64) float64 { return math.Mod(a, b) }
func __Floor(x float64) float64 { return math.Floor(x) }
func __Ceil(x float64) float64 { return math.Ceil(x) }
func __Pow(u float64, v float64) float64 { return math.Pow(u, v) }
func __Sqrt(x float64) float64 { return math.Sqrt(x) }
func __Cbrt(x float64) float64 { return math.Cbrt(x) }
func __Exp(x float64) float64 { return math.Exp(x) }
func __Log(x float64) float64 { return math.Log(x) }
func __Sin(x float64) float64 { return math.Sin(x) }
func __Cos(x float64) float64 { return math.Cos(x) }
func __Tan(x float64) float64 { return math.Tan(x) }
func __Asin(x float64) float64 { return math.Asin(x) }
func __Acos(x float64) float64 { return math.Acos(x) }
func __Atan(x float64) float64 { return math.Atan(x) }
func __Atan2(y float64, x float64) float64 { return math.Atan2(y, x) }
func __Round(x float64) float64 {
	// prevent inlining
	// (__Round unexpectedly replaced into math.Round by Go compiler)
	return (func() float64 { return math.Round(x) })()
}


